home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / calc1a / calc1.bas next >
BASIC Source File  |  1995-05-09  |  7KB  |  346 lines

  1. ' Copyright 1994 C Big Dog Software.  All rights reserved
  2. ' Use in your own products permitted as long as a valid
  3. ' copyright notice is displayed during program initialization
  4. ' along with the following:
  5. '       Portions of this program are Copyright C Big Dog Software
  6. '
  7. Option Explicit
  8. Const mt$ = ""
  9. Const zero% = 0
  10. Const one% = 1
  11. Const two% = 2
  12. Const plus$ = "+"
  13. Const minus$ = "-"
  14. Const times$ = "*"
  15. Const div$ = "/"
  16. Const oparen$ = "("
  17. Const cparen$ = ")"
  18. Const raise$ = "^"
  19. Const UNARY$ = "U"
  20. Dim tokens$(1 To 7)      ' token symbols
  21. Dim tprec%(1 To 7)       ' token precedence (higher is more important)
  22. Dim vstack$(1 To 100)    ' value manipulation
  23. Dim ostack$(1 To 100)    ' operand
  24. Dim vtos%   ' stack pointer of value stack
  25. Dim otos%   ' stack pointer of operand stack
  26. Dim tstr$
  27. Dim calcerr$
  28. Dim pcount% ' paren reduction
  29. Dim lastok%
  30. Const OPERATOR% = 1
  31. Const NUMERIC% = 2
  32.  
  33. Sub clearstacks ()
  34. Dim i%
  35. For i = LBound(ostack) To UBound(ostack)
  36.     ostack(i) = mt
  37. Next
  38. For i = LBound(vstack) To UBound(vstack)
  39.     vstack(i) = mt
  40. Next
  41. initcalc
  42. End Sub
  43.  
  44. Function eval$ (parseme$)
  45. Dim tok$, orig$, otop$
  46. orig = parseme
  47. lastok = OPERATOR
  48. clearstacks
  49. calcerr = mt
  50. pcount = zero
  51. tok = lexx(parseme)
  52. While tok <> mt
  53.     Select Case tok
  54.     Case oparen
  55.         opush tok
  56.     Case cparen
  57.         opush tok
  58.     Case raise
  59.         opush tok
  60.     Case times
  61.         opush tok
  62.     Case div
  63.         opush tok
  64.     Case plus
  65.         opush tok
  66.     Case minus
  67.         If lastok = OPERATOR Then
  68.         opush UNARY
  69.         Else
  70.         opush tok
  71.         End If
  72.     Case Else
  73.         If IsNumeric(tok) Then
  74.         vpush tok
  75.         Else
  76.         eval = "ERROR: Unrecognized token :" + parseme + ":"
  77.         Exit Function
  78.         End If
  79.     End Select
  80.     tok = lexx(parseme)
  81.     If calcerr <> mt Then
  82.     eval = calcerr
  83.     Exit Function
  84.     End If
  85. Wend
  86. reduce
  87. If calcerr <> mt Then
  88.     eval = calcerr
  89. ElseIf vtos <> one Or otos <> zero Then
  90.     If otos <> zero Then
  91.     calcerr = opop()
  92.     If calcerr = oparen Then
  93.         eval = "Mismatched Left Parenthesis ("
  94.     Else
  95.         eval = "Unable to reduce expression due to extra " + calcerr
  96.     End If
  97.     Else
  98.     eval = "Unable to reduce expression"
  99.     End If
  100. Else
  101. ' at this point, the top of stack should contain the value
  102.     eval = vpop()
  103. End If
  104. End Function
  105.  
  106. Function getprec% (tokval$)
  107. ' get token precedence
  108. Dim i%
  109. If tokval = "U" Then
  110.     getprec = 10
  111.     Exit Function
  112. End If
  113. For i = one To UBound(tokens)
  114.     If tokens(i) = tokval Then
  115.     getprec = tprec(i)
  116.     Exit Function
  117.     End If
  118. Next
  119. getprec = 0
  120. End Function
  121.  
  122. Sub initcalc ()
  123. vtos = 0
  124. otos = 0
  125. tokens(1) = "("
  126. tprec(1) = 3
  127. tokens(2) = ")"
  128. tprec(2) = 3
  129. tokens(3) = "*"
  130. tprec(3) = 2
  131. tokens(4) = "/"
  132. tprec(4) = 2
  133. tokens(5) = "+"
  134. tprec(5) = 1
  135. tokens(6) = "-"
  136. tprec(6) = 1
  137. tokens(7) = "^"
  138. tprec(7) = 4
  139. tstr = "()*/+-^"
  140. End Sub
  141.  
  142. Function lexx$ (parsexpr$)
  143. Dim i%, w%, j%, cc$, pl%, hs%, wc$, ft$
  144. hs = Len(parsexpr)
  145. If parsexpr = mt Then
  146.     lexx = mt
  147.     Exit Function
  148. End If
  149. hs = Len(parsexpr)
  150. ft = mt           ' find the FIRST token
  151. For i = one To hs
  152.     cc = Mid$(parsexpr, i, one)
  153.     j = InStr(tstr, cc)
  154.     If j Then
  155.     ft = cc
  156.     Exit For
  157.     End If
  158. Next
  159. If ft <> mt Then
  160.     w = InStr(parsexpr, ft)
  161.     If w Then
  162.     If w = one Then
  163.         lexx = Left$(parsexpr, one)
  164.         parsexpr = Trim$(Mid$(parsexpr, two))
  165.     Else
  166.         lexx = Trim$(Left$(parsexpr, w - one))
  167.         parsexpr = Trim$(Mid$(parsexpr, w))
  168.     End If
  169.     Exit Function
  170.     End If
  171. End If
  172. If IsNumeric(Trim$(parsexpr)) Then
  173.     lexx = Trim$(parsexpr)
  174.     parsexpr = mt
  175. Else
  176.     lexx = mt
  177.     calcerr = "Unrecognized token at start of :" + parsexpr
  178. End If
  179. End Function
  180.  
  181. Function opop$ ()
  182. If otos >= one Then
  183.     opop = ostack(otos)
  184.     ostack(otos) = mt
  185.     otos = otos - one
  186. Else
  187.     opop = mt
  188. End If
  189. End Function
  190.  
  191. Sub opush (pval$)
  192. Dim p1%, p2%
  193. If pval = mt Then Exit Sub
  194. If otos < UBound(ostack) Then
  195.     If otos > zero Then
  196.     If getprec(ostack(otos)) >= getprec(pval) And ostack(otos) <> oparen Then reduce
  197.     End If
  198.     lastok = OPERATOR
  199.     otos = otos + one
  200.     ostack(otos) = pval
  201.     If pval = cparen Then reduce
  202. Else
  203.     calcerr = "Operand Stack blown."
  204. End If
  205. End Sub
  206.  
  207. Sub reduce ()
  208. Dim v1$, v2$, o1$, lt%
  209. o1 = opop()
  210. Select Case o1
  211.     Case mt
  212.     If pcount Then
  213.         calcerr = "Mismatched Right Parenthesis )"
  214.         clearstacks
  215.     End If
  216.     Exit Sub
  217.     Case oparen
  218.     If pcount = zero Then
  219.         lt = lastok
  220.         opush o1
  221.         lastok = lt
  222.         Exit Sub
  223.     End If
  224.     pcount = pcount - one
  225.     If pcount = zero Then Exit Sub
  226.     If pcount < zero Then
  227.         calcerr = "Mismatched Parenthesis"
  228.         clearstacks
  229.     End If
  230.     Case cparen
  231.     pcount = pcount + one
  232.     Case UNARY
  233.     lt = lastok
  234.     vpush "-" + vpop()
  235.     lastok = lt
  236.     Case raise
  237.     v1 = vpop()
  238.     v2 = vpop()
  239.     If v1 = mt Or v2 = mt Then
  240.         calcerr = "Expression error near operand ^"
  241.         clearstacks
  242.         Exit Sub
  243.     End If
  244.     On Error Resume Next
  245.     lt = lastok
  246.     vpush Trim$(Str$(Val(v2) ^ Val(v1)))
  247.     lastok = lt
  248.     If Err Then
  249.         calcerr = "Arithmetic Overflow"
  250.         clearstacks
  251.         Exit Sub
  252.     End If
  253.     On Error GoTo 0
  254.     
  255.     Case times
  256.     v1 = vpop()
  257.     v2 = vpop()
  258.     If v1 = mt Or v2 = mt Then
  259.         calcerr = "Expression error near operand *"
  260.         clearstacks
  261.         Exit Sub
  262.     End If
  263.     On Error Resume Next
  264.     lt = lastok
  265.     vpush Trim$(Str$(Val(v1) * Val(v2)))
  266.     lastok = lt
  267.     If Err Then
  268.         calcerr = "Arithmetic Overflow"
  269.         clearstacks
  270.         Exit Sub
  271.     End If
  272.     On Error GoTo 0
  273.  
  274.     Case div
  275.     v1 = vpop()
  276.     v2 = vpop()
  277.     If v1 = mt Or v2 = mt Then
  278.         calcerr = "Expression error near operand /"
  279.         clearstacks
  280.         Exit Sub
  281.     End If
  282.     If Val(v1) = zero Then
  283.         calcerr = "Division by zero"
  284.         clearstacks
  285.         Exit Sub
  286.     End If
  287.     On Error Resume Next
  288.     lt = lastok
  289.     vpush Trim$(Str$(Val(v2) / Val(v1)))
  290.     lastok = lt
  291.     If Err Then
  292.         calcerr = "Arithmetic Overflow"
  293.         clearstacks
  294.         Exit Sub
  295.     End If
  296.     On Error GoTo 0
  297.  
  298.     Case plus
  299.     v1 = vpop()
  300.     v2 = vpop()
  301.     If v1 = mt Or v2 = mt Then
  302.         calcerr = "Expression error near operand +"
  303.         clearstacks
  304.         Exit Sub
  305.     End If
  306.     lt = lastok
  307.     vpush Trim$(Str$(Val(v2) + Val(v1)))
  308.     lastok = lt
  309.  
  310.     Case minus
  311.     v1 = vpop()
  312.     v2 = vpop()
  313.     If v1 = mt Or v2 = mt Then
  314.         calcerr = "Expression error near operand -"
  315.         clearstacks
  316.         Exit Sub
  317.     End If
  318.     lt = lastok
  319.     vpush Trim$(Str$(Val(v2) - Val(v1)))
  320.     lastok = lt
  321. End Select
  322. reduce
  323. End Sub
  324.  
  325. Function vpop$ ()
  326. If vtos >= one Then
  327.     vpop = vstack(vtos)
  328.     vstack(vtos) = mt
  329.     vtos = vtos - one
  330. Else
  331.     vpop = mt
  332. End If
  333. End Function
  334.  
  335. Sub vpush (pval$)
  336. If pval = mt Then Exit Sub
  337. If vtos < UBound(vstack) Then
  338.     lastok = NUMERIC
  339.     vtos = vtos + one
  340.     vstack(vtos) = pval
  341. Else
  342.     calcerr = "Value Stack blown."
  343. End If
  344. End Sub
  345.  
  346.